package exception

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"
)

// CollectorError 自定义错误类型
type CollectorError struct {
	Code      ErrorCode              `json:"code"`
	Message   string                 `json:"message"`
	Cause     error                  `json:"-"`
	Context   map[string]interface{} `json:"context,omitempty"`
	Timestamp time.Time              `json:"timestamp"`
}

// Error 实现 error 接口
func (e *CollectorError) Error() string {
	if e.Cause != nil {
		return fmt.Sprintf("[%s] %s: %v", e.Code.String(), e.Message, e.Cause)
	}
	return fmt.Sprintf("[%s] %s", e.Code.String(), e.Message)
}

// Unwrap 实现 unwrap 接口
func (e *CollectorError) Unwrap() error {
	return e.Cause
}

// WithContext 添加上下文信息
func (e *CollectorError) WithContext(key string, value interface{}) *CollectorError {
	if e.Context == nil {
		e.Context = make(map[string]interface{})
	}
	e.Context[key] = value
	return e
}

// WithContextMap 添加多个上下文信息
func (e *CollectorError) WithContextMap(ctx map[string]interface{}) *CollectorError {
	if e.Context == nil {
		e.Context = make(map[string]interface{})
	}
	for k, v := range ctx {
		e.Context[k] = v
	}
	return e
}

// ToJSON 将错误序列化为JSON格式
func (e *CollectorError) ToJSON() string {
	data, _ := json.Marshal(e)
	return string(data)
}

// ToJSONDeep 将完整错误链序列化为 JSON
func (e *CollectorError) ToJSONDeep() string {
	type jsonError struct {
		Code    ErrorCode              `json:"code"`
		Message string                 `json:"message"`
		Context map[string]interface{} `json:"context,omitempty"`
		Cause   *jsonError             `json:"cause,omitempty"`
		Time    time.Time              `json:"timestamp"`
	}
	var build func(err *CollectorError) *jsonError
	build = func(err *CollectorError) *jsonError {
		if err == nil {
			return nil
		}
		cause := build(nil)
		var ce *CollectorError
		if errors.As(err.Cause, &ce) {
			cause = build(ce)
		}
		return &jsonError{
			Code:    err.Code,
			Message: err.Message,
			Context: err.Context,
			Cause:   cause,
			Time:    err.Timestamp,
		}
	}
	data, _ := json.Marshal(build(e))
	return string(data)
}

// ErrorStack 以字符串形式返回完整的错误链
func (e *CollectorError) ErrorStack() string {
	if e.Cause != nil {
		var ce *CollectorError
		if errors.As(e.Cause, &ce) {
			return fmt.Sprintf("[%s] %s -> %s", e.Code.String(), e.Message, ce.ErrorStack())
		}
		return fmt.Sprintf("[%s] %s -> %v", e.Code.String(), e.Message, e.Cause)
	}
	return fmt.Sprintf("[%s] %s", e.Code.String(), e.Message)
}

// NewError 创建新的错误
func NewError(code ErrorCode, message string) *CollectorError {
	return &CollectorError{
		Code:      code,
		Message:   message,
		Timestamp: time.Now(),
	}
}

// NewErrorWithCause 创建带原因的错误
func NewErrorWithCause(code ErrorCode, message string, cause error) *CollectorError {
	return &CollectorError{
		Code:      code,
		Message:   message,
		Cause:     cause,
		Timestamp: time.Now(),
	}
}

// WrapError 包装现有错误
func WrapError(code ErrorCode, message string, err error) *CollectorError {
	return NewErrorWithCause(code, message, err)
}

// IsErrorCode 检查错误是否为指定的错误代码
func IsErrorCode(err error, code ErrorCode) bool {
	var collectorErr *CollectorError
	if errors.As(err, &collectorErr) {
		return collectorErr.Code == code
	}
	return false
}

// GetErrorCode 获取错误代码
func GetErrorCode(err error) ErrorCode {
	var collectorErr *CollectorError
	if errors.As(err, &collectorErr) {
		return collectorErr.Code
	}
	return ErrUnknown
}

// IsErrorCodeDeep 沿着因果链进行深度检查
func IsErrorCodeDeep(err error, code ErrorCode) bool {
	for err != nil {
		var ce *CollectorError
		if errors.As(err, &ce) && ce.Code == code {
			return true
		}
		err = errors.Unwrap(err)
	}
	return false
}

// WrapIfErr 将非CollectorError包装为CollectorError
func WrapIfErr(err error, code ErrorCode, msg string) *CollectorError {
	if err == nil {
		return nil
	}
	var ce *CollectorError
	if errors.As(err, &ce) {
		return ce
	}
	return NewErrorWithCause(code, msg, err)
}

// NewConfigError Config 错误
func NewConfigError(message string) *CollectorError {
	return NewError(ErrConfigInvalid, message)
}

// NewConfigLoadError config文件加载失败
func NewConfigLoadError(message string, cause error) *CollectorError {
	return NewErrorWithCause(ErrConfigLoadFailed, message, cause)
}

// NewTaskNotFoundError 任务没有找到错误
func NewTaskNotFoundError(taskID string) *CollectorError {
	return NewError(ErrTaskNotFound, fmt.Sprintf("task not found: %s", taskID))
}

// NewNotTaskIdError task-id 不存在错误
func NewNotTaskIdError(message string) *CollectorError {
	return NewError(ErrTaskIDIsNil, message)
}

// NewTaskCancelledError 任务取消失败
func NewTaskCancelledError(taskID string) *CollectorError {
	return NewError(ErrTaskCancelled, fmt.Sprintf("task %s cancelled", taskID))
}

// NewTaskTimeoutError 收集任务超时
func NewTaskTimeoutError(taskID string, timeout time.Duration) *CollectorError {
	return NewError(ErrTaskTimeoutExceeded,
		fmt.Sprintf("task %s timeout after %v", taskID, timeout))
}

// NewTaskCancelError 创建任务取消失败错误
func NewTaskCancelError(taskID string, cause error) *CollectorError {
	return WrapError(ErrTaskCancelled, fmt.Sprintf("failed to cancel task %s", taskID), cause)
}

// NewTaskExecuteError 任务执行失败
func NewTaskExecuteError(taskID string, cause error) *CollectorError {
	return WrapError(ErrTaskCancelled, fmt.Sprintf("failed to run task %s", taskID), cause)
}

// NewFileNotFoundError 文件未找到错误
func NewFileNotFoundError(filepath string) *CollectorError {
	return NewError(ErrFileNotFound, fmt.Sprintf("file not found: %s", filepath))
}

// NewTaskStatusFileNotFoundError 任务状态文件未找到错误
func NewTaskStatusFileNotFoundError(taskID string) *CollectorError {
	return NewError(ErrTaskStatusFileNotFound, fmt.Sprintf("failed to found task %s", taskID))
}

// NewWriteFileError 写文件失败
func NewWriteFileError(filepath string, cause error) *CollectorError {
	return NewErrorWithCause(ErrFileWriteFailed, fmt.Sprintf("failed to write file: %s", filepath), cause)
}

// NewReadFileError 读文件失败
func NewReadFileError(filepath string, cause error) *CollectorError {
	return NewErrorWithCause(ErrFileReadFailed, fmt.Sprintf("failed to read file: %s", filepath), cause)
}

// NewInvalidPIDError 无效PID信息
func NewInvalidPIDError(filepath string) *CollectorError {
	return NewError(ErrFilePermissionDenied, fmt.Sprintf("read pid file: %s", filepath))
}

// WrapFileError 文件读取失败
func WrapFileError(err error, operation, filepath string) *CollectorError {
	return WrapError(ErrFileReadFailed, fmt.Sprintf("failed to %s file %s", operation, filepath), err)
}

// NewCollectorBaseError 创建 CollectorBase 初始化失败的错误
func NewCollectorBaseError(cause error) *CollectorError {
	return WrapError(ErrCollectorInitFailed, "failed to initialize CollectorBase", cause)
}

// NewSystemError 环境信息不可用
func NewSystemError(message string) *CollectorError {
	return NewError(ErrSystemInfoUnavailable, message)
}

// NewSystemPermissionError 系统权限错误
func NewSystemPermissionError(message string) *CollectorError {
	return NewError(ErrSystemPermissionDenied, message)
}
